package pers.cfeng.server.txManage;

import pers.cfeng.common.DatabaseException;
import pers.cfeng.common.ErrorCode;
import pers.cfeng.server.utils.FaultHandler;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @author Cfeng
 * 本文件定义了事务管理器提供给上层模块的接口调用，包含了事务管理器的所有的基本功能
 * 包括开启事务，提交回滚事务，查询事务状态，关闭TM
 * TM主要都是通过操作tid文件（事务状态文件）实现
 */

public interface TransactionManager {
    long begin(); //开启一个新事务，返回TID
    void commit(long tid); //提交事务
    void rollback(long tid); //回滚事务
    //判断事务状态
    boolean isRunning(long tid);
    boolean isCommitted(long tid);
    boolean isRollback(long tid);
    void close(); //关闭TM

    //静态方法： 创建事务状态文件tid
    static TransactionManagerImpl create(String path) {
        //创建文件
        File file = new File(path + TransactionConstant.TID_SUFFIX);
        try {
            if(!file.createNewFile()) {
                //文件创建失败已存在,直接粗暴处理，因为不能进行后续操作了
                FaultHandler.forcedStop(new DatabaseException(ErrorCode.FILE_EXISTS));
            }
        }catch (Exception e) {
            FaultHandler.forcedStop(e);
        }
        //查看文件是否可读写，直接调用File的接口
        if(!file.canRead() || !file.canWrite()) {
            FaultHandler.forcedStop(new DatabaseException(ErrorCode.FILE_CANNOT_READ_OR_WRITE));
        }
        //使用NIO进行文件读写
        FileChannel fc = null;
        RandomAccessFile raf = null; //与简单IO不同，可以调转到文件任何位置进行IO,访问文件部分内容
        try {
            raf = new RandomAccessFile(file,"rw"); //将file转为随机读写File,文件权限为rw
            fc = raf.getChannel(); //利用randomAccessFile创建channel通道
        } catch (FileNotFoundException e) {
            FaultHandler.forcedStop(e);
        }

        //利用buffer和channel进行文件读写
        //写空的文件头,将byte[]包装为buffer
        ByteBuffer buf = ByteBuffer.wrap(new byte[TransactionConstant.LEN_TID_HEADER_LEN]);
        try {
            fc.position(0); //RandomAccessFile定位到0处开始
            fc.write(buf); //缓冲区写入
        } catch (IOException e) {
            FaultHandler.forcedStop(e);
        }
        return new TransactionManagerImpl(raf, fc);
    }

    //打开tid文件
    public static TransactionManagerImpl open(String path) {
        File file = new File(path + TransactionConstant.TID_SUFFIX);
        if(!file.exists()) {
            FaultHandler.forcedStop(new DatabaseException(ErrorCode.FILE_NOT_EXIST));
        }
        if(!file.canRead() || !file.canWrite()) {
            FaultHandler.forcedStop(new DatabaseException(ErrorCode.FILE_CANNOT_READ_OR_WRITE));
        }
        FileChannel fc = null;
        RandomAccessFile rac = null;
        try {
            rac = new RandomAccessFile(file, "rw");
            fc = rac.getChannel();
        } catch (FileNotFoundException e) {
            FaultHandler.forcedStop(e);
        }
        return new TransactionManagerImpl(rac,fc);
    }
}
